package goutl

import (
	"bufio"
	"gitee.com/xiakai001/goutl/constraints"
	"gitee.com/xiakai001/goutl/errutl"
	"github.com/bytedance/sonic"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	"io"
	"strconv"
	"strings"
)

func Split(s, sep string) []string {

	if len(s) == 0 {
		return []string{}
	}

	return strings.Split(s, sep)
}

func ParseStrToInt[V constraints.Integer](str string) V {
	i, err := strconv.ParseInt(strings.TrimSpace(str), 10, 64)
	errutl.CheckErr(err)

	return V(i)
}

func ParseStrToFloat[V constraints.Float](str string) V {
	i, err := strconv.ParseFloat(strings.TrimSpace(str), 64)
	errutl.CheckErr(err)

	return V(i)
}

func Json(v interface{}) string {
	str, _ := sonic.MarshalString(v)
	return str
}

func JsonFormat(d interface{}) string {
	bs, _ := sonic.MarshalIndent(d, "", "\t")
	return string(bs)
}

func UnMarshal[V any](json string) (V, error) {

	v := Zero[V]()
	err := sonic.UnmarshalString(json, &v)
	if err != nil {
		return v, errutl.Wrap(err)
	}

	return v, nil
}

func MustUnMarshal[V any](json string) V {

	v := Zero[V]()
	err := sonic.UnmarshalString(json, &v)
	if err != nil {
		panic(err)
	}

	return v
}

func NewScanner(reader io.ReadCloser) *Scanner {
	return &Scanner{
		reader: reader,
		r:      bufio.NewReader(reader),
	}
}

type Scanner struct {
	reader       io.ReadCloser
	r            *bufio.Reader
	hasLastBlank bool
}

func (s *Scanner) Next() (string, bool) {

	line, ioErr := s.r.ReadString('\n')
	if ioErr != nil && ioErr != io.EOF {
		panic(ioErr.Error())
	}

	if !s.hasLastBlank && len(line) == 0 && ioErr == io.EOF {
		return "", false
	}

	if len(line) != 0 && line[len(line)-1] == '\n' {
		line = line[0 : len(line)-1]
		s.hasLastBlank = true
	} else {
		s.hasLastBlank = false
	}

	return line, true
}

func (s *Scanner) Close() error {
	return s.reader.Close()
}

func readLinesFromReader[V any](reader io.ReadCloser, top int, skip func(string) bool, deal func(string) V, fn func(index int, line V) error) error {
	if reader == nil {
		return errutl.New("reader is nil!")
	}

	scanner := NewScanner(reader)
	defer func() { _ = scanner.Close() }()

	index := 0
	for {
		line, ok := scanner.Next()
		if !ok {
			break
		}

		if skip != nil && skip(line) {
			continue
		}

		var value V
		if deal != nil {
			value = deal(line)
		} else {
			value = interface{}(line).(V)
		}

		e := fn(index, value)
		if e != nil {
			return errutl.Wrap(e)
		}
		index++

		if top > 0 && index >= top {
			break
		}
	}

	return nil
}

func getStringFromReader(reader io.Reader) (string, error) {
	// 创建 Reader
	r := bufio.NewReader(reader)

	all, err := io.ReadAll(r)
	if err != nil {
		return "", errutl.Wrap(err)
	}

	return string(all), nil
}

func getBytesFromReader(reader io.Reader) ([]byte, error) {
	// 创建 Reader
	r := bufio.NewReader(reader)

	all, err := io.ReadAll(r)
	if err != nil {
		return nil, errutl.Wrap(err)
	}

	return all, nil
}

var (
	commonInitialism  = []string{"id"}
	commonCaseToUpper map[string]string
	casesFn           = cases.Title(language.English, cases.NoLower)
)

func initString() {
	commonCaseToUpper = make(map[string]string, len(commonInitialism))
	for _, initialism := range commonInitialism {
		commonCaseToUpper[casesFn.String(initialism)] = strings.ToUpper(initialism)
	}
}

func UnderscoreToCamel(str string) string {

	arr := strings.Split(strings.ReplaceAll(str, "_", " "), " ")
	for i, s := range arr {
		s = casesFn.String(s)
		upper, ok := commonCaseToUpper[s]
		if ok {
			s = upper
		}
		arr[i] = s
	}

	return strings.Join(arr, "")
}
